package com.zut.blocks.service.grade.impl;

import com.zut.blocks.base.common.request.GradeRequest;
import com.zut.blocks.base.domain.CourseGrade;
import com.zut.blocks.base.domain.Grade;
import com.zut.blocks.base.domain.GroupStudent;
import com.zut.blocks.base.domain.User;
import com.zut.blocks.base.service.impl.GenericServiceImpl;
import com.zut.blocks.dao.course.grade.CourseGradeRepository;
import com.zut.blocks.dao.grade.GradeRepository;
import com.zut.blocks.dao.group.student.GroupStudentRepository;
import com.zut.blocks.dao.user.UserRepository;
import com.zut.blocks.service.grade.CourseGradeService;
import com.zut.blocks.service.grade.GradeService;
import com.zut.blocks.service.grade.vo.FinalGrade;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class GradeServiceImpl extends GenericServiceImpl<Grade, Integer> implements GradeService {

    @Resource
    GradeRepository gradeRepository;

    @Resource
    CourseGradeService courseGradeService;

    @Resource
    GroupStudentRepository groupStudentRepository;

    @Resource
    CourseGradeRepository courseGradeRepository;

    @Resource
    UserRepository userRepository;

    @Override
    public List<Grade> findAll() {
        return gradeRepository.findAll();
    }

    @Override
    public Page<Grade> getGradeById(GradeRequest gradeRequest) {
        return gradeRepository.findAll(gradeRequest.example(), gradeRequest.pageable(true));
    }

    @Override
    public List<FinalGrade> getFinalGradeByCourseId(GradeRequest request) {
        Assert.notNull(request, "request 不能为空");
        Assert.notNull(request.getCourseId(), "course id 不能为空");
        Integer courseId = request.getCourseId();

        List<GroupStudent> students = groupStudentRepository.findAllByCourseId(courseId);
        List<Integer> studentIds = students.stream().map(GroupStudent::getStudentId).collect(Collectors.toList());
        List<User> allCourseUsers = userRepository.findAllById(studentIds);
        Map<Integer, User> userMap = allCourseUsers.stream().collect(Collectors.toMap(User::getId, u -> u));

        List<CourseGrade> courseGradeConfig = courseGradeService.findAllByCourseId(courseId);

        List<Grade> courseGrades = gradeRepository.findAllByCourseId(courseId);
        Map<Integer, Map<Integer, Integer>> idCourseGradeIdGradeSum = courseGrades.stream()
                .collect(Collectors.groupingBy(Grade::getStudentId,
                        Collectors.groupingBy(Grade::getCourseGradeId,
                                Collectors.summingInt(Grade::getGrade))));

        return idCourseGradeIdGradeSum
                .entrySet()
                .stream()
                .map(e -> new FinalGrade(userMap.get(e.getKey()), courseGradeConfig, e.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public Integer upload(MultipartFile file, Integer courseId) {
        // build the mapping of courseConfig and courseGradeId
        List<CourseGrade> allByCourseId = courseGradeRepository.findAllByCourseId(courseId);
        Map<String, Integer> map = new HashMap<>();
        for (CourseGrade courseGrade : allByCourseId) {
            map.put(courseGrade.getName(), courseGrade.getId());
        }

        // read Excel file
        try {
            InputStream inputStream = file.getInputStream();
            Workbook wb = WorkbookFactory.create(inputStream);
            List<Grade> ls = new ArrayList<>();

            for (int sheetIndex = 0; sheetIndex < wb.getNumberOfSheets(); sheetIndex++) {
                Sheet st = wb.getSheetAt(sheetIndex);
                Iterator<Row> iterator = st.iterator();
                iterator.next();
                while (iterator.hasNext()) {
                    Row row = iterator.next();

                    Iterator<Cell> cellIterator = row.cellIterator();
                    ArrayList<Integer> cells = new ArrayList<>();

                    // studentId studentName courseConfig grade
                    if (cellIterator.hasNext()) {
                        Cell cell = cellIterator.next();
                        cells.add((int) cell.getNumericCellValue());
                    }

                    cellIterator.next();
                    if (cellIterator.hasNext()) {
                        Cell cell = cellIterator.next();
                        cells.add(map.get(cell.getStringCellValue()));
                    }

                    if (cellIterator.hasNext()) {
                        Cell cell = cellIterator.next();
                        cells.add((int) cell.getNumericCellValue());
                    }

                    Grade grade = new Grade(cells.get(0), courseId, cells.get(1), cells.get(2));
                    ls.add(grade);
                }
            }
            gradeRepository.saveAll(ls);

        } catch (IOException | InvalidFormatException e) {
            e.printStackTrace();
        }

        return null;
    }
}
